import os
import time
import requests
import openpyxl
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from typing import List, Dict
from moviepy import VideoFileClip


# Constants
URLS_TXT_PATH = 'D:/douyin_download/urls.txt'
USER_LINKS_PATH = 'D:/douyin_download/user.xlsx'
download_excle='D:/douyin_download/download.xlsx'
DOWNLOAD_DIR = 'D:/抖音/视频'
AUDIO_DIR = 'D:/抖音/音频'  # 新增的常量，用于存放 MP3 文件
CHROME_USER_DATA_DIR = "C:/Users/姚望/AppData/Local/Google/Chrome/User Data"
SCROLL_PAUSE_TIME = 10
proxy = {
            'http': 'http://127.0.0.1:8888',
            'https': 'http://127.0.0.1:8888',
        }

def initialize_driver() -> webdriver.Chrome:
    """初始化 Selenium WebDriver."""
    options = webdriver.ChromeOptions()
    # options.add_argument('--headless')  # 无头模式
    options.add_argument('--disable-gpu')  # 禁用 GPU（可选）
    options.add_argument(f"user-data-dir={CHROME_USER_DATA_DIR}")

    # 可指定路径，如 Service('path/to/chromedriver')
    driver = webdriver.Chrome(options=options)
    return driver


def read_urls_from_excel(file_path: str = USER_LINKS_PATH) -> List[str]:
    """从 Excel 文件中读取 URLs."""
    urls = []
    try:
        workbook = openpyxl.load_workbook(file_path)
        sheet = workbook.active
        urls = [cell.value for cell in sheet['A'] if cell.value]
        print(f"从 Excel 读取 {len(urls)} 个 URL.")
    except FileNotFoundError:
        print(f"文件未找到: {file_path}")
    except Exception as e:
        print(f"读取 Excel 时发生错误: {e}")
    return urls

def get_urls_from_webdriver(urls: List[str]) -> None:
    """使用 Selenium WebDriver 访问并滚动每个 URL."""
    driver = initialize_driver()
    print("浏览器已打开。")
    try:
        for url in urls:
            driver.get(url)
            print(f"访问 URL: {url}")
            # time.sleep(5)
            container = WebDriverWait(driver, 30).until(
                EC.presence_of_element_located((By.XPATH, '//*[@id="user-tabbar-2"]/div[2]/div/div'))
            )
            print("找到容器元素。")
            scroll_container(driver)
    except Exception as e:
        print(f"发生异常: {e}")
    finally:
        time.sleep(10)
        driver.quit()
        print("浏览器已关闭。")

def read_url_parameters(file_path: str = URLS_TXT_PATH) -> List[Dict[str, str]]:
    """
    读取 URLS_TXT_PATH 文件并解析每个段落的 requestURL, Cookie, User-Agent, Referer.
    
    文件格式示例:
    requestURL: https://www.douyin.com/aweme/1
    Cookie: ttwid=1%7C--54IaQ...
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
    Referer: https://www.douyin.com/user/MS4wLjAB...
    
    ---
    
    requestURL: https://www.douyin.com/aweme/2
    Cookie: ttwid=1%7C--54IaQ...
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
    Referer: https://www.douyin.com/user/MS4wLjAB...
    """
    parameters_list = []
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        # os.remove(file_path)
        # Split content into paragraphs separated by two newlines
        paragraphs = content.strip().split('\n\n')
        for para in paragraphs:
            param = {}
            lines = para.strip().split('\n')
            for line in lines:
                if ':' in line:
                    key, value = line.split(':', 1)
                    param[key.strip()] = value.strip()
            if {'requestURL', 'Cookie', 'User-Agent', 'Referer'}.issubset(param.keys()):
                parameters_list.append(param)
            else:
                print("警告: 某个段落缺少必要的字段。")
        print(f"从文件读取 {len(parameters_list)} 组参数。")
    except FileNotFoundError:
        print(f"文件未找到: {file_path}")
    except Exception as e:
        print(f"读取文件时发生错误: {e}")
    return parameters_list





def scroll_container(driver: webdriver.Chrome) -> None:
    """滚动指定的容器并根据指定元素的出现情况决定是否继续滚动."""
    try:
        container1 = WebDriverWait(driver, 30).until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="douyin-right-container"]/div[2]'))
        )
        last_height = driver.execute_script("return arguments[0].scrollHeight", container1)
        print(f"初始容器高度: {last_height}")
        
        while True:
            time.sleep(SCROLL_PAUSE_TIME)
            driver.execute_script("arguments[0].scrollTo(0, arguments[0].scrollHeight);", container1)
            # 判断指定元素是否出现
            try:
                time.sleep(SCROLL_PAUSE_TIME)
                # 替换 'YOUR_SPECIFIED_XPATH' 为实际的 XPath

                x = driver.find_element(By.XPATH, '//*[@id="douyin-right-container"]/div[2]/div/div/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div').text
                #
                if x=='暂时没有更多了':
                    print("指定元素已出现，停止滚动。" + x)
                    break
                else:
                    print("指定元素未出现，继续滚动。")
                    continue
            except Exception:
                print("指定元素未出现，继续滚动。")
    except Exception as e:
        print(f"滚动过程中发生错误: {e}")


def sanitize_filename(filename: str) -> str:
    """清理文件名中的非法字符."""
    return "".join(c for c in filename if c.isalnum() or c in (' ', '_', '-')).rstrip()


def download_video():
    """
    下载视频，读取每组参数并执行下载操作，并将视频URL保存到Excel中。
    """
    parameters_list = read_url_parameters()
    excel_path = 'video_urls.xlsx'
    
    # 读取或创建Excel文件
    try:
        wb = openpyxl.load_workbook(excel_path)
        ws = wb.active
        existing_urls = set(cell.value for cell in ws['A'] if cell.value)
    except FileNotFoundError:
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = 'Video URLs'
        existing_urls = set()
        ws['A1'] = 'Video URL'  # 添加表头
    
    for params in parameters_list:
        headers = {
            'Cookie': params['Cookie'],
            'User-Agent': params['User-Agent'],
            'Referer': params['Referer']
        }

        requestURL = params['requestURL']
        
        try:
            res = requests.get(requestURL, headers=headers, proxies=proxy, verify=False)
            res.raise_for_status()
            aweme_list = res.json().get("aweme_list", [])
            for aweme in aweme_list:
                title = aweme.get("desc", "untitled").replace('\n','').strip()
                video_url = aweme.get("video", {}).get("play_addr", {}).get("url_list", [-1])[-1]
                if video_url == -1:
                    print(f"未找到视频 URL: {requestURL}")
                    continue
                
                # 检查URL是否已存在
                if video_url not in existing_urls:
                    ws.append([video_url])
                    existing_urls.add(video_url)
                    print(f"新URL已添加到Excel: {video_url}")
                    print(f"下载视频: {video_url}")
                    download_video_content(video_url, title, headers)
                else:
                    print(f"URL已存在，跳过: {video_url}")
                
                
                
            # 保存Excel文件
            wb.save(excel_path)
            
        except requests.RequestException as e:
            print(f"请求错误: {e}")
        except ValueError:
            print(f"JSON 解析错误: {requestURL}")
        except Exception as e:
            print(f"保存Excel时发生错误: {e}")


def download_video_content(video_url: str, title: str, headers: Dict[str, str]) -> None:
    """
    下载视频内容并保存到本地。
    
    Args:
        video_url (str): 视频下载的 URL。
        title (str): 视频的标题，用于命名文件。
        headers (Dict[str, str]): HTTP 请求头，包含 Cookie、User-Agent 和 Referer。

    """
    try:
        response = requests.get(video_url, timeout=10,headers=headers,proxies=proxy,verify=False)
        # print(response.content)
        response.raise_for_status()
        os.makedirs(DOWNLOAD_DIR, exist_ok=True)
        safe_title = sanitize_filename(title)
        file_path = os.path.join(DOWNLOAD_DIR, f"{safe_title}.mp4")
        with open(file_path, 'wb') as f:
            f.write(response.content)
        print(f"已下载并保存视频: {file_path}")
    except requests.RequestException as e:
        print(f"下载视频失败: {e}")
    except Exception as e:
        print(f"保存视频时发生错误: {e}")


def extract_audio_from_all_videos() -> None:
    """
    遍历下载目录中的所有视频文件，提取音频并保存为 mp3 文件。
    """
    print("开始批量提取音频...")
    os.makedirs(AUDIO_DIR, exist_ok=True)
    for filename in os.listdir(DOWNLOAD_DIR):
        if filename.lower().endswith('.mp4'):
            video_path = os.path.join(DOWNLOAD_DIR, filename)
            try:
                clip = VideoFileClip(video_path)
                audio = clip.audio
                if audio:
                    mp3_path = os.path.join(AUDIO_DIR, os.path.splitext(filename)[0] + '.mp3')
                    audio.write_audiofile(mp3_path)
                    print(f"已提取音频并保存为: {mp3_path}")
                else:
                    print(f"视频中未找到音频: {video_path}")
            except Exception as e:
                print(f"提取音频时发生错误 ({video_path}): {e}")
    print("音频提取完成。")


def main():
    """主函数."""
    # 示例：从 Excel 读取 URLs 并使用 WebDriver 处理
    urls = read_urls_from_excel()
    if urls:
        get_urls_from_webdriver(urls)

    # 示例：下载视频
    # download_video()
    # 所有视频下载完成后，提取音频
    # extract_audio_from_all_videos()


if __name__ == "__main__":
    main()
